/*
 * @copyright fxsen <br/>
 * @date 2022/4/18 15:01 <br/>
 * @email <a href="mailto:fxsen@foxmail.com">
 * @author fxsen
 */
package com.fxsen.commons.sysmanager.core.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fxsen.commons.core.annotation.RecordLog;
import com.fxsen.commons.core.base.common.service.impl.CommonServiceImpl;
import com.fxsen.commons.sysmanager.core.entity.OperationLog;
import com.fxsen.commons.sysmanager.core.mapper.OperationLogMapper;
import com.fxsen.commons.sysmanager.core.service.IOperationLogService;
import com.fxsen.commons.utils.HttpContextUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 操作日志接口实现
 * @author fxsen
 * @date 2022/4/18 15:01
 * @email <a href="mailto:fxsen@foxmail.com">
 */
@Service
public class OperationLogServiceImpl extends CommonServiceImpl<OperationLogMapper,OperationLog> implements IOperationLogService {
    @Override
    public void recordOperationLog(String operationUser, String name, int type,String exMessage,HttpServletRequest request, String methodName) {
        String ipAddress = HttpContextUtils.getIpAddress(request);
        /*String param = HttpContextUtils.getBodyString(request);
        if (StringUtils.isBlank(param)){
            param = JSON.toJSONString(HttpContextUtils.getParameterMapAll(request));
        }*/
        String param = JSON.toJSONString(HttpContextUtils.getParameterMapAll(request));
        OperationLog operationLog = new OperationLog();
        operationLog.setType(type);
        operationLog.setOperationUser(operationUser);
        operationLog.setRequestIp(ipAddress);
        operationLog.setRealAddress(HttpContextUtils.getIpAddr(ipAddress));
        operationLog.setRequestUrl(request.getRequestURL().toString());
        operationLog.setName(name);
        operationLog.setParam(param);
        if (StringUtils.isNotBlank(methodName)){
            operationLog.setMethodName(methodName);
        }
        if (StringUtils.isNotBlank(exMessage)){
            operationLog.setExMessage(exMessage);
        }
        operationLog.setRequestMethod(request.getMethod());
        save(operationLog);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, OperationLog log) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RecordLog recordLog = method.getAnnotation(RecordLog.class);
        // 方法路径
        String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        log.setName(recordLog.value());
        log.setRequestIp(ip);
        log.setRealAddress(HttpContextUtils.getIpAddr(ip));
        log.setMethodName(methodName);
        log.setOperationUser(username);
        log.setBrowser(browser);
        log.setParam(getParameter(method, joinPoint.getArgs()));
        save(log);
    }
    /**
     * 根据方法和传入的参数获取请求参数
     */
    private String getParameter(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //将RequestBody注解修饰的参数作为请求参数
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }
            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>();
                String key = parameters[i].getName();
                if (!StringUtils.isEmpty(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (argList.size() == 0) {
            return "";
        }
        return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
    }
}
